﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OPCAutomation;
using System.Net;
using NLog;
using OPCService.Model;

namespace OPCService.Service
{
    class OPCClientService
    {
        private static readonly Logger logger = NLog.LogManager.GetCurrentClassLogger();
        private List<string> servers = new List<string>();
        private List<string> nodes = new List<string>();
        private List<Item> values = new List<Item>();
        private readonly Dictionary<string, OPCGroup> groupsDict = new Dictionary<string, OPCGroup>();
        private readonly Dictionary<string, OPCItem> itemsDict = new Dictionary<string, OPCItem>();
        public OPCServer KepServer;

        #region 私有变量

        /// <summary>
        /// OPCGroups Object
        /// </summary>
        OPCGroups KepGroups;

        /// <summary>
        /// OPCGroup Object
        /// </summary>
        OPCGroup KepGroup;

        /// <summary>
        /// OPCItems Object
        /// </summary>
        OPCItems KepItems;

        /// <summary>
        /// OPCItem Object
        /// </summary>
        OPCItem KepItem;

        /// <summary>
        /// 主机IP
        /// </summary>
        string remoteServerIP = "";

        /// <summary>
        /// 主机名称
        /// </summary>
        string remoteServerName = "";

        /// <summary>
        /// 连接状态
        /// </summary>
        bool opc_connected = false;

        /// <summary>
        /// 客户端句柄
        /// </summary>
        int itmHandleClient = 0;

        /// <summary>
        /// 服务端句柄
        /// </summary>
        int itmHandleServer = 0;
        #endregion

        public OPCClientService(string serverIp, string serverName)
        {
            KepServer = new OPCServer();
            remoteServerName = serverName;
            remoteServerIP = serverIp;
        }

        #region 方法
        /// <summary>
        /// 枚举本地OPC服务器
        /// </summary>
        public List<string> GetLocalServer()
        {
            //获取本地计算机上的OPCServerName
            try
            {
                object serverList = KepServer.GetOPCServers(remoteServerName);

                foreach (string turn in (Array)serverList)
                {
                    servers.Add(turn);
                }
            }
            catch (Exception err)
            {
                logger.Warn("枚举本地OPC服务器出错：" + err.Message, "提示信息");
            }

            return servers;

        }

        /// <summary>
        /// 连接OPC服务器
        /// </summary>
        public bool Connect()
        {
            try
            {
                KepServer.Connect(remoteServerName, remoteServerIP);

                if (KepServer.ServerState == (int)OPCServerState.OPCRunning)
                {
                    //tsslServerState.Text = "已连接到-" + KepServer.ServerName + "   ";
                    Console.WriteLine("已连接到-" + KepServer.ServerName);
                }
                else
                {
                    //这里你可以根据返回的状态来自定义显示信息，请查看自动化接口API文档
                    //tsslServerState.Text = "状态：" + KepServer.ServerState.ToString() + "   ";
                    Console.WriteLine("状态：" + KepServer.ServerState.ToString());
                }
            }
            catch (Exception err)
            {
                Console.WriteLine("连接远程服务器出现错误：" + err.Message, "提示信息");
                return false;
            }
            return true;
        }

        /// <summary>
        /// 断开连接OPC服务器
        /// </summary>
        public void Disconnect()
        {
            if (KepServer != null && KepServer.ServerState == (int)OPCServerState.OPCRunning)
            {
                KepServer.Disconnect();
                Console.WriteLine("Disconnected from OPC server.");
            }
        }

        /// <summary>
        /// 创建组
        /// </summary>
        public OPCGroup AddGroup(string groupName)
        {
            try
            {
                KepGroups = KepServer.OPCGroups;
                KepGroup = KepGroups.Add(groupName);
                SetGroupProperty((true, 0, 250, true, true)); //参数元祖类型
                KepGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange);
                KepGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete);
                KepItems = KepGroup.OPCItems;
                groupsDict.Add(groupName, KepGroup);
            }
            catch (Exception err)
            {
                logger.Warn("创建组出现错误：" + err.Message);
            }
            return KepGroup;
        }

        /// <summary>
        /// 设置组属性
        /// </summary>
        public void SetGroupProperty((bool groupIsActive, int groupDeadband, int updateRate, bool isActive, bool isSubscribed) properties)
        {
            KepServer.OPCGroups.DefaultGroupIsActive = properties.groupIsActive;
            KepServer.OPCGroups.DefaultGroupDeadband = properties.groupDeadband;
            KepGroup.UpdateRate = properties.updateRate;
            KepGroup.IsActive = properties.isActive;
            KepGroup.IsSubscribed = properties.isSubscribed;
        }

        /// <summary>
        /// 列出OPC服务器中所有节点
        /// </summary>
        /// <param name="oPCBrowser"></param>
        public List<string> RecurBrowse(OPCBrowser oPCBrowser)
        {
            //展开分支
            oPCBrowser.ShowBranches();
            //展开叶子
            oPCBrowser.ShowLeafs(true);
            int num = 0;
            foreach (object turn in oPCBrowser)
            {
                nodes.Add(turn.ToString());
                num++;
            }
            return nodes;
        }

        /// <summary>
        /// 获取服务器信息，并显示在窗体状态栏上
        /// </summary>
        private void GetServerInfo()
        {
            //tsslServerStartTime.Text = "开始时间:" + KepServer.StartTime.ToString() + "    ";
            //tsslversion.Text = "版本:" + KepServer.MajorVersion.ToString() + "." + KepServer.MinorVersion.ToString() + "." + KepServer.BuildNumber.ToString();
            Console.WriteLine("开始时间:" + KepServer.StartTime.ToString());
            Console.WriteLine("版本:" + KepServer.MajorVersion.ToString() + "." + KepServer.MinorVersion.ToString() + "." + KepServer.BuildNumber.ToString());
        }

        /// <summary>
        /// 添加项
        /// </summary>
        public bool AddItem(string groupName, string itemName)
        {
            try
            {
                if (groupsDict.TryGetValue(groupName, out OPCGroup opcGroup))
                {
                    OPCItems opcItems = opcGroup.OPCItems;
                    OPCItem opcItem = opcItems.AddItem(itemName, opcItems.Count + 1); //需要一个唯一的 clientHandle 来标识每个添加的 OPCItem
                    itemsDict.Add(itemName, opcItem);
                    return true;
                }
                else
                {
                    Console.WriteLine($"Group '{groupName}' not found.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error adding item to OPC group: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 添加项
        /// </summary>
        public bool AddItems(string groupName, List<string> itemNames)
        {
            try
            {
                if (groupsDict.TryGetValue(groupName, out OPCGroup opcGroup))
                {
                    OPCItems opcItems = opcGroup.OPCItems;
                    for (int i = 0; i < itemNames.Count; i++)
                    {
                        int itmHandleClient = i + 1;
                        OPCItem opcItem = opcItems.AddItem(itemNames[i], itmHandleClient);
                        itemsDict.Add(itemNames[i], opcItem);
                    }

                    /*OPCItems opcItems = opcGroup.OPCItems;
                    Array itemIDs = Array.CreateInstance(typeof(string), itemNames.Count);
                    Array clientHandles = Array.CreateInstance(typeof(int), itemNames.Count);
                    Array serverHandles = Array.CreateInstance(typeof(int), itemNames.Count);
                    Array errors = Array.CreateInstance(typeof(int), itemNames.Count);
                    int index = opcItems.Count;
                    for (int i = 0; i < itemNames.Count; i++)
                    {
                        logger.Warn(itemNames[i] + "===========AddItems=========000000000=========>" + index);
                        index++;
                        itemIDs.SetValue(itemNames[i], i);
                        clientHandles.SetValue(index, i);
                    }

                    // 添加 TAG 到组
                    opcItems.AddItems(itemNames.Count, itemIDs, clientHandles, out serverHandles, out errors) ;*/
                    return true;
                }
                else
                {
                    Console.WriteLine($"======Group '{groupName}' not found.========");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error adding item to OPC group: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 读取单条数据
        /// </summary>
        public object ReadItemValue(string groupName, string itemName)
        {
            try
            {
                if (groupsDict.TryGetValue(groupName, out OPCGroup opcGroup))
                {
                    OPCItems opcItems = opcGroup.OPCItems;
                    if (itemsDict.TryGetValue(itemName, out OPCItem opcItem))
                    {
                        opcItem.Read(1, out object value, out object quality, out object timeStamp);
                        return value;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error reading item value: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 写单条数据
        /// </summary>
        public bool WriteItemValue(string groupName, string itemName, object value)
        {
            try
            {
                if (groupsDict.TryGetValue(groupName, out OPCGroup opcGroup))
                {
                    OPCItems opcItems = opcGroup.OPCItems;
                    if (itemsDict.TryGetValue(itemName, out OPCItem opcItem))
                    {
                        opcItem.Write(value);
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    Console.WriteLine($"Group '{groupName}' not found.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error writing value to item {itemName}: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 写批量数据
        /// </summary>
        public bool WriteItemValues(string groupName, Dictionary<string, object> itemValues)
        {
            try
            {
                if (groupsDict.TryGetValue(groupName, out OPCGroup opcGroup))
                {
                    OPCItems opcItems = opcGroup.OPCItems;

                    //异步写时，Array数组从下标1开始而非0！
                    int[] tempServerHandles = new int[opcItems.Count + 1];
                    object[] tempValues = new object[opcItems.Count + 1];
                    int index = 0;
                    tempServerHandles[index] = 0;
                    tempValues[index] = "";

                    foreach (KeyValuePair<string, object> kvp in itemValues)
                    {
                        index++;
                        if (itemsDict.TryGetValue(kvp.Key, out OPCItem opcItem))
                        {
                            tempServerHandles[index] = opcItem.ServerHandle;
                            tempValues[index] = kvp.Value;
                        }
                    }

                    Array opcItemServerHandles = (Array)tempServerHandles;
                    Array opcItemValues = (Array)tempValues;
                    Array errors;
                    int cancelID;
                    opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete);
                    opcGroup.AsyncWrite(itemValues.Count, ref opcItemServerHandles, ref opcItemValues, out errors, 0, out cancelID);

                    return true;
                }
                else
                {
                    Console.WriteLine($"Group '{groupName}' not found.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error writing values to items: {ex.Message}");
                return false;
            }
        }
        #endregion

        #region 事件
        /// <summary>
        /// 写入TAG值时执行的事件
        /// </summary>
        /// <param name="TransactionID"></param>
        /// <param name="NumItems"></param>
        /// <param name="ClientHandles"></param>
        /// <param name="Errors"></param>
        void KepGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
        {
            //lblState.Text = "";
            for (int i = 1; i <= NumItems; i++)
            {
                //lblState.Text += "Tran:" + TransactionID.ToString() + "   CH:" + ClientHandles.GetValue(i).ToString() + "   Error:" + Errors.GetValue(i).ToString();
                Console.WriteLine("Tran:" + TransactionID.ToString() + "   CH:" + ClientHandles.GetValue(i).ToString() + "   Error:" + Errors.GetValue(i).ToString());
            }
        }

        /// <summary>
        /// 每当项数据有变化时执行的事件
        /// </summary>
        /// <param name="TransactionID">处理ID</param>
        /// <param name="NumItems">项个数</param>
        /// <param name="ClientHandles">项客户端句柄</param>
        /// <param name="ItemValues">TAG值</param>
        /// <param name="Qualities">品质</param>
        /// <param name="TimeStamps">时间戳</param>
        void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
        {
            //为了测试，所以加了控制台的输出，来查看事物ID号
            //Console.WriteLine("********"+TransactionID.ToString()+"*********");
            for (int i = 1; i <= NumItems; i++)
            {
                Item item = new Item();
                item.tag_name = ClientHandles.GetValue(i).ToString();
                item.value = double.Parse(ItemValues.GetValue(i).ToString());
                item.quality = Qualities.GetValue(i).ToString();
                item.datetime = Convert.ToDateTime(TimeStamps.GetValue(i).ToString());
                values.Add(item);
            }
        }
        #endregion
    }
}
